package xyz.thoughtset.viewer.common.envvar.factory;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import xyz.thoughtset.viewer.common.envvar.annotation.EnvPropSign;
import xyz.thoughtset.viewer.common.envvar.constants.EnvVarDataTypeConstant;
import xyz.thoughtset.viewer.common.envvar.entity.EnvVars;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

@Component
public class EnvPropSignFactory {
    @Value("${scan.package}")
    private String scanPackage;
    @Autowired
    protected ObjectMapper objectMapper;
    @Autowired
    protected ApplicationContext applicationContext;

    private Map<String, Class> signMap = new HashMap<>();
                private Map<String, String> LinkMap = new HashMap<>();

                @PostConstruct
                public void init() {
                    // 创建扫描器，false 表示不检查父类
                    ClassPathScanningCandidateComponentProvider scanner =
                            new ClassPathScanningCandidateComponentProvider(false);
                    scanner.addIncludeFilter(new AnnotationTypeFilter(EnvPropSign.class));
                    // 扫描指定包
                    Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(scanPackage);
                    for (BeanDefinition beanDefinition : beanDefinitions) {
                        try {
                            Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());
                            EnvPropSign envPropSign = clazz.getAnnotation(EnvPropSign.class);
                String key = envPropSign.name();
                if (!StringUtils.hasText(key)) {
                    key = StringUtils.uncapitalize(clazz.getSimpleName());
                }
//                String parent = envPropSign.parent();
//                if(StringUtils.hasText(parent)){
//                    LinkMap.put(key,parent);
//                }
                signMap.put(key,clazz);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    public EnvPropSign getSignInfo(Class key) {
        return (EnvPropSign) key.getAnnotation(EnvPropSign.class);
    }
    public EnvPropSign getSignInfo(String key) {
        return (EnvPropSign) signMap.get(key).getAnnotation(EnvPropSign.class);
    }
    public Class getType(String key) {
        return signMap.get(key);
    }

    public Object getTargetData(String topic,Object payload) {
        Class clazz = findTrueType((Map) payload,topic);
        return objectMapper.convertValue(payload,clazz);
    }

    @SneakyThrows
    public Object loadData(EnvVars data) {
        if (Objects.isNull(data)) {
            return null;
        }
        Object result = data.getPayload();
        if (Objects.isNull(result)) {
            return null;
        }
        result = objectMapper.readValue(data.getPayload(), Map.class);
        return objectMapper.convertValue(result,findTrueType((Map) result,data.getTopic()));
//        if (!(EnvVarDataTypeConstant.OBJ.equals(data.getType()))) {
//            return data.getPayload();
//        }
//        Object result = data.getPayload();
//        switch (data.getType()) {
//            case EnvVarDataTypeConstant.MAP:
//                result = objectMapper.convertValue(data.getPayload(), Map.class);
//                break;
//            case EnvVarDataTypeConstant.OBJ:
//                break;
//            default: break;
//        }
//        return result;
//        return objectMapper.convertValue(data.getPayload(),getSignType(data.getTopic()));
    }

    private Class findTrueType(Map baseMap,String topic) {
        Class<?> clazz = null;
        String next = topic;
        do{
            clazz = signMap.get(next);
            EnvPropSign sign = clazz.getAnnotation(EnvPropSign.class);
            if (Objects.isNull(sign)) {
                return null;
            }
            if (clazz == Void.class) {
                return null;
            }
            next = sign.field();
            if(StringUtils.hasText(next)){
                Object nextKey = baseMap.get(next);
                if (nextKey.getClass().isEnum()) {
                    next = ((Enum) nextKey).name();
                }
                next = (String) baseMap.get(next);
            }
        }while (StringUtils.hasText(next));
        return clazz;
    }



}
